home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpuzzles.3 / xpuzzles / xpuzzles-5.3.1 / xrubik / Rubik.c < prev    next >
C/C++ Source or Header  |  1996-04-11  |  28KB  |  1,018 lines

  1. /*
  2. # X-BASED RUBIK'S CUBE(tm)
  3. #
  4. #  Rubik.c
  5. #
  6. ###
  7. #
  8. #  Copyright (c) 1994 - 96    David Albert Bagley, bagleyd@hertz.njit.edu
  9. #
  10. #                   All Rights Reserved
  11. #
  12. #  Permission to use, copy, modify, and distribute this software and
  13. #  its documentation for any purpose and without fee is hereby granted,
  14. #  provided that the above copyright notice appear in all copies and
  15. #  that both that copyright notice and this permission notice appear in
  16. #  supporting documentation, and that the name of the author not be
  17. #  used in advertising or publicity pertaining to distribution of the
  18. #  software without specific, written prior permission.
  19. #
  20. #  This program is distributed in the hope that it will be "playable",
  21. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  23. #
  24. */
  25.  
  26. /* Methods file for Rubik */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #ifdef VMS
  31. #include <unixlib.h>
  32. #else
  33. #ifndef apollo
  34. #include <unistd.h>
  35. #endif
  36. #endif
  37. #include <X11/IntrinsicP.h>
  38. #include <X11/Intrinsic.h>
  39. #include <X11/StringDefs.h>
  40. #include <X11/CoreP.h>
  41. #include "RubikP.h"
  42. #include "Rubik2dP.h"
  43. #include "Rubik3dP.h"
  44.  
  45. #ifndef DATAFILE
  46. #define DATAFILE "/usr/games/lib/rubik.data"
  47. #endif
  48.  
  49. static void InitializeRubik();
  50. static void DestroyRubik();
  51. static Boolean SetValuesRubik();
  52. static void GetColor();
  53. static void MoveControlCb();
  54. static void CheckPolyhedrons();
  55. static int SelectPolyhedrons();
  56. static int NarrowSelection();
  57. static int PositionPolyhedrons();
  58. static void MoveNoPolyhedrons();
  59. static void PracticePolyhedrons();
  60. static void RandomizePolyhedrons();
  61. static void MovePolyhedrons();
  62. /* rc : row or column */
  63. static void ReadRc();
  64. static void RotateRc();
  65. static void ReverseRc();
  66. static void WriteRc();
  67. static void RotateFace();
  68. static void DrawSquare();
  69. static int CheckMoveDir();
  70.  
  71. RubikClassRec rubikClassRec =
  72. {
  73.   {
  74.     (WidgetClass) &widgetClassRec,    /* superclass */
  75.     "Rubik",                /* class name */
  76.     sizeof(RubikRec),            /* widget size */
  77.     NULL,                /* class initialize */
  78.     NULL,                /* class part initialize */
  79.     FALSE,                /* class inited */
  80.     InitializeRubik,            /* initialize */
  81.     NULL,                /* initialize hook */
  82.     XtInheritRealize,            /* realize */
  83.     NULL,                /* actions */
  84.     0,                    /* num actions */
  85.     NULL,                /* resources */
  86.     0,                    /* num resources */
  87.     NULLQUARK,                /* xrm class */
  88.     TRUE,                /* compress motion */
  89.     TRUE,                /* compress exposure */
  90.     TRUE,                /* compress enterleave */
  91.     TRUE,                /* visible interest */
  92.     DestroyRubik,            /* destroy */
  93.     NULL,                /* resize */
  94.     NULL,                /* expose */
  95.     SetValuesRubik,            /* set values */
  96.     NULL,                /* set values hook */
  97.     XtInheritSetValuesAlmost,        /* set values almost */
  98.     NULL,                /* get values hook */
  99.     NULL,                /* accept focus */
  100.     XtVersion,                /* version */
  101.     NULL,                /* callback private */
  102.     NULL,                /* tm table */
  103.     NULL,                /* query geometry */
  104.     NULL,                /* display accelerator */
  105.     NULL                /* extension */
  106.   },
  107.   {
  108.     0                    /* ignore */
  109.   }
  110. };
  111.  
  112. WidgetClass rubikWidgetClass = (WidgetClass) &rubikClassRec;
  113.  
  114. static RubikLoc slideNextRow[MAXFACES][MAXORIENT] =
  115. {
  116.   {{5, STRT}, {3,   CW}, {2, STRT}, {1,  CCW}},
  117.   {{0,   CW}, {2, STRT}, {4,  CCW}, {5, HALF}},
  118.   {{0, STRT}, {3, STRT}, {4, STRT}, {1, STRT}},
  119.   {{0,  CCW}, {5, HALF}, {4,   CW}, {2, STRT}},
  120.   {{2, STRT}, {3,  CCW}, {5, STRT}, {1,   CW}},
  121.   {{4, STRT}, {3, HALF}, {0, STRT}, {1, HALF}}
  122. };
  123. static int rowToRotate[MAXFACES][MAXORIENT] =
  124. {
  125.   {3, 2, 1, 5},
  126.   {2, 4, 5, 0},
  127.   {3, 4, 1, 0},
  128.   {5, 4, 2, 0},
  129.   {3, 5, 1, 2},
  130.   {3, 0, 1, 4}
  131. };
  132.  
  133. static void InitializeRubik(request, new)
  134.   Widget request, new;
  135. {
  136.   RubikWidget w = (RubikWidget) new;
  137.   XGCValues values;
  138.   XtGCMask valueMask;
  139.   int face, orient;
  140.  
  141.   for (face = 0; face < MAXFACES; face++)
  142.     w->rubik.cubeLoc[face] = NULL;
  143.   for (orient = 0; orient < MAXORIENT; orient++)
  144.     w->rubik.rowLoc[orient] = NULL;
  145.   w->rubik.faceLoc = NULL;
  146.   CheckPolyhedrons(w);
  147.   InitMoves();
  148.   ResetPolyhedrons(w);
  149.   (void) SRAND(getpid());
  150.   valueMask = GCForeground | GCBackground;
  151.   values.background = w->core.background_pixel;
  152.   values.foreground = w->rubik.foreground;
  153.   w->rubik.puzzleGC = XtGetGC(new, valueMask, &values);
  154.   values.foreground = w->rubik.borderColor;
  155.   w->rubik.borderGC = XtGetGC(new, valueMask, &values);
  156.   w->rubik.depth = DefaultDepthOfScreen(XtScreen(w));
  157.   valueMask = GCForeground | GCBackground;
  158.   values.foreground = w->core.background_pixel;
  159.   values.background = w->rubik.foreground;
  160.   w->rubik.inverseGC = XtGetGC(new, valueMask, &values);
  161.   for (face = 0; face < MAXFACES; face++)
  162.     GetColor(w, face, TRUE);
  163. }
  164.  
  165. static void DestroyRubik(old)
  166.   Widget old;
  167. {
  168.   RubikWidget w = (RubikWidget) old;
  169.   int face;
  170.  
  171.   for (face = 0; face < MAXFACES; face++)
  172.     XtReleaseGC(old, w->rubik.faceGC[face]);
  173.   XtReleaseGC(old, w->rubik.borderGC);
  174.   XtReleaseGC(old, w->rubik.puzzleGC);
  175.   XtReleaseGC(old, w->rubik.inverseGC);
  176.   XtRemoveCallbacks(old, XtNselectCallback, w->rubik.select);
  177. }
  178.  
  179. static Boolean SetValuesRubik(current, request, new)
  180.   Widget current, request, new;
  181. {
  182.   RubikWidget c = (RubikWidget) current, w = (RubikWidget) new;
  183.   XGCValues values;
  184.   XtGCMask valueMask;
  185.   Boolean redraw = FALSE;
  186.   int face;
  187.  
  188.   CheckPolyhedrons(w);
  189.   if (w->rubik.foreground != c->rubik.foreground) {
  190.     valueMask = GCForeground | GCBackground;
  191.     values.foreground = w->rubik.foreground;
  192.     values.background = w->core.background_pixel;
  193.     XtReleaseGC(new, w->rubik.puzzleGC);
  194.     w->rubik.puzzleGC = XtGetGC(new, valueMask, &values);
  195.   }
  196.   if (w->core.background_pixel != c->core.background_pixel) {
  197.     valueMask = GCForeground | GCBackground;
  198.     values.foreground = w->core.background_pixel;
  199.     values.background = w->rubik.foreground;
  200.     XtReleaseGC(new, w->rubik.inverseGC);
  201.     w->rubik.inverseGC = XtGetGC(new, valueMask, &values);
  202.     redraw = TRUE;
  203.   }
  204.   if (w->rubik.borderColor != c->rubik.borderColor) {
  205.     valueMask = GCForeground | GCBackground;
  206.     values.foreground = w->rubik.borderColor;
  207.     values.background = w->core.background_pixel;
  208.     XtReleaseGC(new, w->rubik.borderGC);
  209.     w->rubik.borderGC = XtGetGC(new, valueMask, &values);
  210.     redraw = TRUE;
  211.   }
  212.   if (w->rubik.mono || w->rubik.depth == 1) {
  213.     valueMask = GCForeground | GCBackground;
  214.     values.background = w->core.background_pixel;
  215.     values.foreground = w->rubik.foreground;
  216.     for (face = 0; face < MAXFACES; face++) {
  217.       XtReleaseGC(new, w->rubik.faceGC[face]);
  218.       w->rubik.faceGC[face] = XtGetGC(new, valueMask, &values);
  219.     }
  220.     redraw = TRUE;
  221.   }
  222.   for (face = 0; face < MAXFACES; face++) {
  223.     if (strcmp(w->rubik.faceName[face], c->rubik.faceName[face]))
  224.       GetColor(w, face, FALSE);
  225.   }
  226.   if (w->rubik.orient != c->rubik.orient) {
  227.     ResetPolyhedrons(w);
  228.     redraw = TRUE;
  229.   } else if (w->rubik.practice != c->rubik.practice) {
  230.     ResetPolyhedrons(w);
  231.     redraw = TRUE;
  232.   }
  233.   if (w->rubik.currentDirection == RUBIK_RESTORE) {
  234.     SetStartPosition(w);
  235.     w->rubik.currentDirection = RUBIK_IGNORE;
  236.   } else if (w->rubik.currentDirection != RUBIK_IGNORE) {
  237.     MovePolyhedrons(w, w->rubik.currentFace, w->rubik.currentPosition,
  238.      w->rubik.currentDirection);
  239.     w->rubik.currentDirection = RUBIK_IGNORE;
  240.   }
  241.   return redraw;
  242. }
  243.  
  244. void QuitRubik(w, event, args, nArgs)
  245.   RubikWidget w;
  246.   XEvent *event;
  247.   char *args[];
  248.   int nArgs;
  249. {
  250.   XtCloseDisplay(XtDisplay(w));
  251.   exit(0);
  252. }
  253.  
  254. void SelectRubik(w, event, args, nArgs)
  255.   RubikWidget w;
  256.   XEvent *event;
  257.   char *args[];
  258.   int nArgs;
  259. {
  260.   int control;
  261.  
  262.   if (SelectPolyhedrons(w, event->xbutton.x, event->xbutton.y,
  263.              &(w->rubik.currentFace), &(w->rubik.currentPosition))) {
  264.     control = (int) (event->xkey.state & ControlMask);
  265.     if (control || w->rubik.practice || !CheckSolved(w))
  266.       DrawSquare(w, w->rubik.currentFace, w->rubik.currentPosition,
  267.         TRUE);
  268.   } else {
  269.     w->rubik.currentFace = RUBIK_IGNORE;
  270.     w->rubik.currentDirection = RUBIK_IGNORE;
  271.   }
  272. }
  273.  
  274. void ReleaseRubik(w, event, args, nArgs)
  275.   RubikWidget w;
  276.   XEvent *event;
  277.   char *args[];
  278.   int nArgs;
  279. {
  280.   int control, face, position, count = -1, direction = 0;
  281.   rubikCallbackStruct cb;
  282.  
  283.   if (w->rubik.currentFace == RUBIK_IGNORE)
  284.     return;
  285.   DrawSquare(w, w->rubik.currentFace, w->rubik.currentPosition, FALSE);
  286.   control = (int) (event->xkey.state & ControlMask);
  287.   if (!control && !w->rubik.practice && CheckSolved(w))
  288.     MoveNoPolyhedrons(w);
  289.   else if (SelectPolyhedrons(w, event->xbutton.x, event->xbutton.y,
  290.              &face, &position)) {
  291.     control = (control) ? 1 : 0;
  292.     if (face == w->rubik.currentFace)
  293.       count = CheckMoveDir(w, w->rubik.currentPosition, position, &direction);
  294.     if (count == 1) {
  295.       MoveRubik(w, face, w->rubik.currentPosition, direction, control);
  296.       if (!control && CheckSolved(w)) {
  297.         cb.reason = RUBIK_SOLVED;
  298.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  299.       }
  300.     } else if (count == 0)
  301.       MoveNoPolyhedrons(w);
  302.   }
  303. }
  304.  
  305. void PracticeRubik(w, event, args, nArgs)
  306.   RubikWidget w;
  307.   XEvent *event;
  308.   char *args[];
  309.   int nArgs;
  310. {
  311.   PracticePolyhedrons(w);
  312. }
  313.  
  314. void PracticeRubikMaybe(w, event, args, nArgs)
  315.   RubikWidget w;
  316.   XEvent *event;
  317.   char *args[];
  318.   int nArgs;
  319. {
  320.   if (!w->rubik.started)
  321.     PracticePolyhedrons(w);
  322. }
  323.  
  324. void RandomizeRubik(w, event, args, nArgs)
  325.   RubikWidget w;
  326.   XEvent *event;
  327.   char *args[];
  328.   int nArgs;
  329. {
  330.   RandomizePolyhedrons(w);
  331. }
  332.  
  333. void RandomizeRubikMaybe(w, event, args, nArgs)
  334.   RubikWidget w;
  335.   XEvent *event;
  336.   char *args[];
  337.   int nArgs;
  338. {
  339.   if (!w->rubik.started)
  340.     RandomizePolyhedrons(w);
  341. }
  342.  
  343. void GetRubik(w, event, args, nArgs)
  344.   RubikWidget w;
  345.   XEvent *event;
  346.   char *args[];
  347.   int nArgs;
  348. {
  349.   FILE *fp;
  350.   char c;
  351.   int i, size, orient, practice, moves;
  352.   rubikCallbackStruct cb;
  353.  
  354.   if ((fp = fopen(DATAFILE, "r")) == NULL)
  355.     (void) printf("Can not read %s for get.\n", DATAFILE);
  356.   else {
  357.     FlushMoves(w);
  358.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  359.     (void) fscanf(fp, "%d", &size);
  360.     if (size >= MINCUBES) {
  361.       for (i = w->rubik.size; i < size; i++) {
  362.         cb.reason = RUBIK_INC;
  363.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  364.       }  
  365.       for (i = w->rubik.size; i > size; i--) {
  366.         cb.reason = RUBIK_DEC;
  367.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  368.       }
  369.     } else
  370.       (void) printf("%s corrupted: size %d should be between %d and MAXINT\n",
  371.          DATAFILE, size, MINCUBES);
  372.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  373.     (void) fscanf(fp, "%d", &orient);
  374.     if (w->rubik.orient != (Boolean) orient) {
  375.       cb.reason = RUBIK_ORIENT;
  376.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  377.     }
  378.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  379.     (void) fscanf(fp, "%d", &practice);
  380.     if (w->rubik.practice != (Boolean) practice) {
  381.       cb.reason = RUBIK_PRACTICE;
  382.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  383.     }
  384.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  385.     (void) fscanf(fp, "%d", &moves);
  386.     ScanStartPosition(fp, w);
  387.     cb.reason = RUBIK_RESTORE;
  388.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  389.     ScanMoves(fp, w, moves);
  390.     (void) fclose(fp);
  391.     (void) printf("%s: size %d, orient %d, practice %d, moves %d.\n",
  392.       DATAFILE, size, orient, practice, moves);
  393.   }
  394. }
  395.  
  396. void WriteRubik(w, event, args, nArgs)
  397.   RubikWidget w;
  398.   XEvent *event;
  399.   char *args[];
  400.   int nArgs;
  401. {
  402.   FILE *fp;
  403.  
  404.   if ((fp = fopen(DATAFILE, "w")) == NULL)
  405.     (void) printf("Can not write to %s.\n", DATAFILE);
  406.   else {
  407.     (void) fprintf(fp, "size%c %d\n", SYMBOL, w->rubik.size);
  408.     (void) fprintf(fp, "orient%c %d\n", SYMBOL, (w->rubik.orient) ? 1 : 0);
  409.     (void) fprintf(fp, "practice%c %d\n", SYMBOL, (w->rubik.practice) ? 1 : 0);
  410.     (void) fprintf(fp, "moves%c %d\n", SYMBOL, NumMoves());
  411.     PrintStartPosition(fp, w);
  412.     PrintMoves(fp);
  413.     (void) fclose(fp);
  414.     (void) printf("Saved to %s.\n", DATAFILE);
  415.   }
  416. }
  417.  
  418. void UndoRubik(w, event, args, nArgs)
  419.   RubikWidget w;
  420.   XEvent *event;
  421.   char *args[];
  422.   int nArgs;
  423. {
  424.   if (MadeMoves()) {
  425.     int face, position, direction, control;
  426.  
  427.     GetMove(&face, &position, &direction, &control);
  428.     direction = (direction < MAXORIENT) ? (direction + MAXORIENT / 2) %
  429.       MAXORIENT : 3 * MAXORIENT - direction;
  430.     if (control)
  431.       MoveControlCb(w, face, direction);
  432.     else {
  433.       rubikCallbackStruct cb;
  434.  
  435.       MovePolyhedrons(w, face, position, direction);
  436.       cb.reason = RUBIK_UNDO;
  437.       cb.face = face;
  438.       cb.position = position;
  439.       cb.direction = direction;
  440.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  441.     }
  442.   }
  443. }
  444.  
  445. void SolveRubik(w, event, args, nArgs)
  446.   RubikWidget w;
  447.   XEvent *event;
  448.   char *args[];
  449.   int nArgs;
  450. {
  451.   if (w->rubik.size <= 2 || (w->rubik.size == 3 && !w->rubik.orient))
  452.     SolvePolyhedrons(w);
  453. }
  454.  
  455. void IncrementRubik(w, event, args, nArgs)
  456.   RubikWidget w;
  457.   XEvent *event;
  458.   char *args[];
  459.   int nArgs;
  460. {
  461.   rubikCallbackStruct cb;
  462.  
  463.   cb.reason = RUBIK_INC;
  464.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  465. }
  466.  
  467. void DecrementRubik(w, event, args, nArgs)
  468.   RubikWidget w;
  469.   XEvent *event;
  470.   char *args[];
  471.   int nArgs;
  472. {
  473.   rubikCallbackStruct cb;
  474.  
  475.   if (w->rubik.size <= MINCUBES)
  476.     return;
  477.   cb.reason = RUBIK_DEC;
  478.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  479. }
  480.  
  481. void OrientizeRubik(w, event, args, nArgs)
  482.   RubikWidget w;
  483.   XEvent *event;
  484.   char *args[];
  485.   int nArgs;
  486. {
  487.   rubikCallbackStruct cb;
  488.  
  489.   cb.reason = RUBIK_ORIENT;
  490.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  491. }
  492.  
  493. void MoveRubikCcw(w, event, args, nArgs)
  494.   RubikWidget w;
  495.   XEvent *event;
  496.   char *args[];
  497.   int nArgs;
  498. {
  499.   MoveRubikInput(w, event->xbutton.x, event->xbutton.y, CCW,
  500.     (int) (event->xbutton.state & ControlMask));
  501. }
  502.  
  503. void MoveRubikCw(w, event, args, nArgs)
  504.   RubikWidget w;
  505.   XEvent *event;
  506.   char *args[];
  507.   int nArgs;
  508. {
  509.   MoveRubikInput(w, event->xbutton.x, event->xbutton.y, CW,
  510.     (int) (event->xkey.state & ControlMask));
  511. }
  512.  
  513. void MoveRubikInput(w, x, y, direction, control)
  514.   RubikWidget w;
  515.   int x, y, direction, control;
  516. {
  517.   int face, position;
  518.  
  519.   if (!w->rubik.practice && !control && CheckSolved(w)) {
  520.     MoveNoPolyhedrons(w);
  521.     return;
  522.   }
  523.   if (!PositionPolyhedrons(w, x, y, &face, &position, &direction))
  524.     return;
  525.   control = (control) ? 1 : 0;
  526.   MoveRubik(w, face, position, direction, control);
  527.   if (!control && CheckSolved(w)) {
  528.     rubikCallbackStruct cb;
  529.  
  530.     cb.reason = RUBIK_SOLVED;
  531.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  532.   }
  533. }
  534.  
  535. void MoveRubik(w, face, position, direction, control)
  536.   RubikWidget w;
  537.   int face, position, direction, control;
  538. {
  539.   if (control)
  540.     MoveControlCb(w, face, direction);
  541.   else {
  542.     rubikCallbackStruct cb;
  543.  
  544.     MovePolyhedrons(w, face, position, direction);
  545.     cb.reason = RUBIK_MOVED;
  546.     cb.face = face;
  547.     cb.position = position;
  548.     cb.direction = direction;
  549.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  550.   }
  551.   PutMove(face, position, direction, control);
  552. }
  553.  
  554. static void GetColor(w, face, init)
  555.   RubikWidget w;
  556.   int face, init;
  557. {
  558.   XGCValues values;
  559.   XtGCMask valueMask;
  560.   XColor colorCell, rgb;
  561.  
  562.   valueMask = GCForeground | GCBackground;
  563.   values.background = w->core.background_pixel;
  564.   if (w->rubik.depth > 1 && !w->rubik.mono) {
  565.     if (XAllocNamedColor(XtDisplay(w),
  566.         DefaultColormap(XtDisplay(w), XtWindow(w)),
  567.         w->rubik.faceName[face], &colorCell, &rgb)) {
  568.       values.foreground = w->rubik.faceColor[face] = colorCell.pixel;
  569.       if (!init)
  570.         XtReleaseGC((Widget) w, w->rubik.faceGC[face]);
  571.       w->rubik.faceGC[face] = XtGetGC((Widget) w, valueMask, &values);
  572.       return;
  573.     } else {
  574.       char buf[121];
  575.  
  576.       (void) sprintf(buf, "Color name \"%s\" is not defined",
  577.                w->rubik.faceName[face]);
  578.       XtWarning(buf);
  579.     }
  580.   }
  581.   values.foreground = w->rubik.foreground;
  582.   if (!init)
  583.     XtReleaseGC((Widget) w, w->rubik.faceGC[face]);
  584.   w->rubik.faceGC[face] = XtGetGC((Widget) w, valueMask, &values);
  585. }
  586.  
  587. static void MoveControlCb(w, face, direction)
  588.   RubikWidget w;
  589.   int face, direction;
  590. {
  591.   rubikCallbackStruct cb;
  592.   int k, position;
  593.  
  594.   for (k = 0; k < w->rubik.size; k++) {
  595.     position = k * w->rubik.size + k;
  596.     MovePolyhedrons(w, face, position, direction);
  597.     cb.reason = RUBIK_CONTROL;
  598.     cb.face = face;
  599.     cb.position = position;
  600.     cb.direction = direction;
  601.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  602.   }
  603. }
  604.  
  605. static void CheckPolyhedrons(w)
  606.   RubikWidget w;
  607. {
  608.   if (w->rubik.size < MINCUBES) {
  609.     char buf[121];
  610.  
  611.     (void) sprintf(buf, "Number of Cubes on edge out of bounds, use %d..MAXINT",
  612.              MINCUBES);
  613.     XtWarning(buf);
  614.     w->rubik.size = DEFAULTCUBES;
  615.   }
  616. }
  617.  
  618. void ResetPolyhedrons(w)
  619.   RubikWidget w;
  620. {
  621.   int face, position, orient;
  622.  
  623.   w->rubik.sizeSize = w->rubik.size * w->rubik.size;
  624.   for (face = 0; face < MAXFACES; face++) {
  625.     if (w->rubik.cubeLoc[face])
  626.       (void) free((void *) w->rubik.cubeLoc[face]);
  627.     if (!(w->rubik.cubeLoc[face] = (RubikLoc *)
  628.           malloc(sizeof(RubikLoc) * w->rubik.sizeSize)))
  629.       XtError("Not enough memory, exiting.");
  630.     if (startLoc[face])
  631.       (void) free((void *) startLoc[face]);
  632.     if (!(startLoc[face] = (RubikLoc *)
  633.           malloc(sizeof(RubikLoc) * w->rubik.sizeSize)))
  634.       XtError("Not enough memory, exiting.");
  635.   }
  636.   for (orient = 0; orient < MAXORIENT; orient++) {
  637.     if (w->rubik.rowLoc[orient])
  638.       (void) free((void *) w->rubik.rowLoc[orient]);
  639.     if (!(w->rubik.rowLoc[orient] = (RubikLoc *)
  640.           malloc(sizeof(RubikLoc) * w->rubik.size)))
  641.       XtError("Not enough memory, exiting.");
  642.   }
  643.   if (w->rubik.faceLoc)
  644.     (void) free((void *) w->rubik.faceLoc);
  645.   if (!(w->rubik.faceLoc = (RubikLoc *)
  646.         malloc(sizeof(RubikLoc) * w->rubik.sizeSize)))
  647.     XtError("Not enough memory, exiting.");
  648.   for (face = 0; face < MAXFACES; face++)
  649.     for (position = 0; position < w->rubik.sizeSize; position++) {
  650.       w->rubik.cubeLoc[face][position].face = face; 
  651.       w->rubik.cubeLoc[face][position].rotation = STRT - MAXORIENT;
  652.     }
  653.   FlushMoves(w);
  654.   w->rubik.started = FALSE;
  655. }
  656.  
  657. static int SelectPolyhedrons(w, x, y, face, position)
  658.   RubikWidget w;
  659.   int x, y;
  660.   int *face;
  661.   int *position;
  662. {
  663.   if (w->rubik.dim == 2)
  664.     return SelectPolyhedrons2D((Rubik2DWidget) w, x, y,
  665.       face, position);
  666.   else if (w->rubik.dim == 3)
  667.     return SelectPolyhedrons3D((Rubik3DWidget) w, x, y,
  668.       face, position);
  669.   return FALSE;
  670. }
  671.  
  672. static int NarrowSelection(w, face, position, direction)
  673.   RubikWidget w;
  674.   int *face;
  675.   int *position;
  676.   int *direction;
  677. {
  678.   if (w->rubik.dim == 2)
  679.     return NarrowSelection2D((Rubik2DWidget) w, face, position, direction);
  680.   else if (w->rubik.dim == 3)
  681.     return NarrowSelection3D((Rubik3DWidget) w, face, position, direction);
  682.   return FALSE;
  683. }
  684.  
  685. static int PositionPolyhedrons(w, x, y, face, position, direction)
  686.   RubikWidget w;
  687.   int x, y;
  688.   int *face;
  689.   int *position;
  690.   int *direction;
  691. {
  692.   if (!SelectPolyhedrons(w, x, y, face, position))
  693.     return FALSE;
  694.   return NarrowSelection(w, face, position, direction);
  695. }
  696.  
  697. static void MoveNoPolyhedrons(w)
  698.   RubikWidget w;
  699. {
  700.   rubikCallbackStruct cb;
  701.  
  702.   cb.reason = RUBIK_ILLEGAL;
  703.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  704. }
  705.  
  706. static void PracticePolyhedrons(w)
  707.   RubikWidget w;
  708. {
  709.   rubikCallbackStruct cb;
  710.  
  711.   cb.reason = RUBIK_PRACTICE;
  712.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  713. }
  714.  
  715. static void RandomizePolyhedrons(w)
  716.   RubikWidget w;
  717. {
  718.   rubikCallbackStruct cb;
  719.   int face, position, direction;
  720.   int big = w->rubik.sizeSize * 3 + NRAND(2);
  721.  
  722.   if (big > 1000)
  723.     big = 1000;
  724.   if (w->rubik.practice)
  725.     PracticePolyhedrons(w);
  726.   cb.reason = RUBIK_RESET;
  727.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  728.  
  729. #ifdef DEBUG
  730.   big = 3;
  731. #endif
  732.  
  733.   while (big--) {
  734.     face = NRAND(MAXFACES);
  735.     position = NRAND(w->rubik.sizeSize);
  736.     direction = NRAND(MAXORIENT);
  737.     MoveRubik(w, face, position, direction, FALSE);
  738.   }
  739.   FlushMoves(w);
  740.   cb.reason = RUBIK_RANDOMIZE;
  741.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  742.   if (CheckSolved(w)) {
  743.     cb.reason = RUBIK_SOLVED;
  744.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  745.   }
  746. }
  747.  
  748. static void MovePolyhedrons(w, face, position, direction)
  749.   RubikWidget w;
  750.   int face, position, direction;
  751. {
  752.   int newFace, newDirection, rotate, reverse = FALSE, h, k, newH = 0;
  753.   int i, j;
  754.  
  755.   i = position % w->rubik.size;
  756.   j = position / w->rubik.size;
  757.   h = (direction == TOP || direction == BOTTOM) ? i : j;
  758.   /* rotate sides CW or CCW */
  759.   if (h == w->rubik.size - 1) {
  760.     newDirection = (direction == TOP || direction == BOTTOM) ?
  761.       TOP : RIGHT;
  762.     if (direction == TOP || direction == RIGHT)
  763.       RotateFace(w, rowToRotate[face][newDirection], CW);
  764.     else /* direction == BOTTOM || direction == LEFT */
  765.       RotateFace(w, rowToRotate[face][newDirection], CCW);
  766.   }
  767.   if (h == 0) {
  768.     newDirection = (direction == TOP || direction == BOTTOM) ?
  769.       BOTTOM : LEFT;
  770.     if (direction == TOP || direction == RIGHT)
  771.       RotateFace(w, rowToRotate[face][newDirection], CCW);
  772.     else /* direction == BOTTOM  || direction == LEFT */
  773.       RotateFace(w, rowToRotate[face][newDirection], CW);
  774.   }
  775.   /* Slide rows */
  776.   ReadRc(w, face, direction, h, 0);
  777.   for (k = 1; k <= MAXORIENT; k++) {
  778.     newFace = slideNextRow[face][direction].face;
  779.     rotate = slideNextRow[face][direction].rotation;
  780.     newDirection = (rotate + direction) % MAXORIENT;
  781.     switch (rotate) {
  782.       case STRT:
  783.         newH = h;
  784.         reverse = FALSE;
  785.         break;
  786.       case CW:
  787.         if (newDirection == TOP || newDirection == BOTTOM) {
  788.           newH = w->rubik.size - 1 - h;
  789.           reverse = FALSE;
  790.         } else /* newDirection == RIGHT || newDirection == LEFT */ {
  791.           newH = h;
  792.           reverse = TRUE;
  793.         }
  794.         break;
  795.       case HALF:
  796.         newH = w->rubik.size - 1 - h;
  797.         reverse = TRUE;
  798.         break;
  799.       case CCW:
  800.         if (newDirection == TOP || newDirection == BOTTOM) {
  801.           newH = h;
  802.           reverse = TRUE;
  803.         } else /* newDirection == RIGHT || newDirection == LEFT */ {
  804.           newH = w->rubik.size - 1 - h;
  805.           reverse = FALSE;
  806.         }
  807.         break;
  808.       default:
  809.         (void) printf ("MovePolyhedrons: rotate %d\n", rotate);
  810.     }
  811.     if (k != MAXORIENT)
  812.       ReadRc(w, newFace, newDirection, newH, k);
  813.     RotateRc(w, rotate, k - 1);
  814.     if (reverse == TRUE)
  815.       ReverseRc(w, k - 1);
  816.     WriteRc(w, newFace, newDirection, newH, k - 1);
  817.     face = newFace;
  818.     direction = newDirection;
  819.     h = newH;
  820.   }
  821. }
  822.  
  823. static void ReadRc(w, face, dir, h, orient)
  824.   RubikWidget w;
  825.   int face, dir, h, orient;
  826. {
  827.   int g;
  828.  
  829.   if (dir == TOP || dir == BOTTOM)
  830.     for (g = 0; g < w->rubik.size; g++)
  831.       w->rubik.rowLoc[orient][g] =
  832.         w->rubik.cubeLoc[face][g * w->rubik.size + h];
  833.   else /* dir == RIGHT || dir == LEFT */
  834.     for (g = 0; g < w->rubik.size; g++)
  835.       w->rubik.rowLoc[orient][g] =
  836.         w->rubik.cubeLoc[face][h * w->rubik.size + g];
  837. }
  838.  
  839. static void RotateRc(w, rotate, orient)
  840.   RubikWidget w;
  841.   int rotate, orient;
  842. {
  843.   int g;
  844.  
  845.   for (g = 0; g < w->rubik.size; g++)
  846.     w->rubik.rowLoc[orient][g].rotation =
  847.       (w->rubik.rowLoc[orient][g].rotation + rotate) % MAXORIENT;
  848. }
  849.  
  850. static void ReverseRc(w, orient)
  851.   RubikWidget w;
  852.   int orient;
  853. {
  854.   int g;
  855.   RubikLoc temp;
  856.  
  857.   for (g = 0; g < w->rubik.size / 2; g++) {
  858.     temp = w->rubik.rowLoc[orient][w->rubik.size - 1 - g];
  859.     w->rubik.rowLoc[orient][w->rubik.size - 1 - g] = w->rubik.rowLoc[orient][g];
  860.     w->rubik.rowLoc[orient][g] = temp;
  861.   }
  862. }
  863.  
  864. static void WriteRc(w, face, dir, h, orient)
  865.   RubikWidget w;
  866.   int face, dir, h, orient;
  867. {
  868.   int g, position;
  869.  
  870.   if (dir == TOP || dir == BOTTOM) {
  871.     for (g = 0; g < w->rubik.size; g++) {
  872.       position = g * w->rubik.size + h;
  873.       w->rubik.cubeLoc[face][position] = w->rubik.rowLoc[orient][g];
  874.       DrawSquare(w, face, position, FALSE);
  875.     }
  876.   } else /* dir == RIGHT || dir == LEFT */ {
  877.     for (g = 0; g < w->rubik.size; g++) {
  878.       position = h * w->rubik.size + g;
  879.       w->rubik.cubeLoc[face][position] = w->rubik.rowLoc[orient][g];
  880.       DrawSquare(w, face, position, FALSE);
  881.     }
  882.   }
  883. }
  884.  
  885. static void RotateFace(w, face, direction)
  886.   RubikWidget w;
  887.   int face, direction;
  888. {
  889.   int position, i, j;
  890.  
  891.   /* Read Face */
  892.   for (position = 0; position < w->rubik.sizeSize; position++)
  893.     w->rubik.faceLoc[position] = w->rubik.cubeLoc[face][position];
  894.   /* Write Face */
  895.   for (position = 0; position < w->rubik.sizeSize; position++) {
  896.     i = position % w->rubik.size;
  897.     j = position / w->rubik.size;
  898.     w->rubik.cubeLoc[face][position] = (direction == CW) ?
  899.       w->rubik.faceLoc[(w->rubik.size - i - 1) * w->rubik.size + j]:
  900.       w->rubik.faceLoc[i * w->rubik.size + w->rubik.size - j - 1];
  901.     w->rubik.cubeLoc[face][position].rotation =
  902.       (w->rubik.cubeLoc[face][position].rotation + direction - MAXORIENT) %
  903.       MAXORIENT;
  904.     DrawSquare(w, face, position, FALSE);
  905.   }
  906. }
  907.  
  908. void DrawAllPolyhedrons(w)
  909.   RubikWidget w;
  910. {
  911.   int face, position;
  912.  
  913.   for (face = 0; face < MAXFACES; face++)
  914.     for (position = 0; position < w->rubik.sizeSize; position++)
  915.       DrawSquare(w, face, position, FALSE);
  916. }
  917.  
  918. static void DrawSquare(w, face, position, offset)
  919.   RubikWidget w;
  920.   int face, position, offset;
  921. {
  922.   if (w->rubik.dim == 2)
  923.     DrawSquare2D((Rubik2DWidget) w, face, position, offset);
  924.   else if (w->rubik.dim == 3)
  925.     DrawSquare3D((Rubik3DWidget) w, face, position, offset);
  926. }
  927.  
  928. Boolean CheckSolved(w)
  929.   RubikWidget w;
  930. {
  931.   int face, position;
  932.   RubikLoc test;
  933.  
  934.   for (face = 0; face < MAXFACES; face++)
  935.     for (position = 0; position < w->rubik.sizeSize; position++) {
  936.       if (!position) {
  937.         test.face = w->rubik.cubeLoc[face][position].face;
  938.         test.rotation = w->rubik.cubeLoc[face][position].rotation;
  939.       } else if (test.face != /*face*/
  940.                w->rubik.cubeLoc[face][position].face ||
  941.                (w->rubik.orient && test.rotation != /*STRT - MAXORIENT*/
  942.                 w->rubik.cubeLoc[face][position].rotation))
  943.         return FALSE;
  944.     }
  945.   return TRUE;
  946. }
  947.  
  948. static int CheckMoveDir(w, position1, position2, direction)
  949.   RubikWidget w;
  950.   int position1, position2, *direction;
  951. {
  952.   int count = 0;
  953.   int column1, column2, row1, row2;
  954.  
  955.   column1 = position1 % w->rubik.size;
  956.   column2 = position2 % w->rubik.size;
  957.   row1 = position1 / w->rubik.size;
  958.   row2 = position2 / w->rubik.size;
  959.   if (column1 == column2 && row1 != row2) {
  960.     *direction = (row2 > row1) ? BOTTOM : TOP;
  961.     count = 1;
  962.   } else if (row1 == row2 && column1 != column2) {
  963.     *direction = (column2 > column1) ? RIGHT : LEFT;
  964.     count = 1;
  965.   } else if (row1 == row2 && column1 == column2)
  966.     count = 2;
  967.   return count;
  968. }
  969.  
  970.  
  971. #ifdef DEBUG
  972.  
  973. void PrintCube(w)
  974.   RubikWidget w;
  975. {
  976.   int face, position;
  977.  
  978.   for (face = 0; face < MAXFACES; face++) {
  979.     for (position = 0; position < w->rubik.sizeSize; position++) {
  980.        (void) printf("%d %d  ", w->rubik.cubeLoc[face][position].face,
  981.                 w->rubik.cubeLoc[face][position].rotation);
  982.        if (!((position + 1) % w->rubik.size))
  983.          (void) printf("\n");
  984.     }
  985.     (void) printf("\n");
  986.   }
  987.   (void) printf("\n");
  988. }
  989.  
  990. void PrintFace(w)
  991.   RubikWidget w;
  992. {
  993.   int position;
  994.  
  995.   for (position = 0; position < w->rubik.sizeSize; position++) {
  996.      (void) printf("%d %d  ", w->rubik.faceLoc[position].face,
  997.               w->rubik.faceLoc[position].rotation);
  998.      if (!((position + 1) % w->rubik.size))
  999.        (void) printf("\n");
  1000.   }
  1001.   (void) printf("\n");
  1002. }
  1003.  
  1004. void PrintRow(w, orient)
  1005.   RubikWidget w;
  1006.   int orient;
  1007. {
  1008.   int i;
  1009.  
  1010.   (void) printf("Row %d:\n", orient);
  1011.   for (i = 0; i < w->rubik.size; i++)
  1012.     (void) printf("%d %d  ", w->rubik.rowLoc[orient][i].face,
  1013.              w->rubik.rowLoc[orient][i].rotation);
  1014.   (void) printf("\n");
  1015. }
  1016.  
  1017. #endif
  1018.